/*
 *      Author: Honrun
 */
#include "stdint.h"
#include "stdio.h"
#include "gd32l23x.h"
#include "DevicesTime.h"
#include "DevicesKey.h"


static KeyStateEnum enumKeyStateGet(uint32_t uiNew, uint32_t uiOld);
static KeyStateEnum enumKeyTimeStateGet(KeyType *ptypeKey);


KeyType g_typeKey;


void vKeyInit(void)
{
    syscfg_pin_remap_enable(SYSCFG_BOOT0_PD3_REMAP);

    /* enable the GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOD);

    gpio_bit_set(KEY_POWER_GPIO_Port, KEY_POWER_Pin);

    /* configure key pin as input */
    gpio_mode_set(KEY_POWER_GPIO_Port, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, KEY_POWER_Pin);

    g_typeKey.uiKeyValueGet = uiKeyValueGet;
}

/*
Return Value:   按键组合序号（头文件里有定义）
Parameters:     void
Description:    读取当前按键状态
*/
uint32_t uiKeyValueGet(void)
{
    uint32_t Key = KEY_POWER;
    uint8_t i;

    for(i = 0; i < 8; ++i)
    {
        if(RESET != gpio_input_bit_get(KEY_POWER_GPIO_Port, KEY_POWER_Pin))
            Key &= ~KEY_POWER;
    }

    return Key;
}

/*
 * Return:      按键状态
 * Parameters:  Value_new:新按键键值; Value_old:旧按键键值;
 * Description: 按键状态获取
 */
static KeyStateEnum enumKeyStateGet(uint32_t uiNew, uint32_t uiOld)
{
    if(uiNew == uiOld)                      /* 当前按键值与上次按键值相同 */
        return keyEqual;
    else if((uiNew & uiOld) == uiOld)       /* 当前按键值在上次按键值基础上增加了新按键 */
        return keyAdd;
    else if((uiNew | uiOld) == uiOld)       /* 当前按键值在上次按键值基础上减少了旧按键 */
        return keyCut;
    else                                    /* 当前按键值在上次按键值基础上即减少了旧按键又增加了新按键 */
        return keyAddAndCut;
}

/*
 * Return:      KeyStateEnum：按键状态机的状态
 * Parameters:  ptypeKey: 按键结构消息
 * Description: 按键状态获取
 */
static KeyStateEnum enumKeyTimeStateGet(KeyType *ptypeKey)
{
    int32_t lTimeNow = lTimebaseGet() / 1000;

    switch((uint32_t)ptypeKey->state)
    {
        case keyAdd:
            if((lTimeNow - ptypeKey->timePress) >= KEY_SHORT_TIME)
            {
                ptypeKey->state &= 0x00FF;
                ptypeKey->state |= keyShort;
                return ptypeKey->state;
            }
            break;

        case keyShort | keyAdd:
            if((lTimeNow - ptypeKey->timePress) >= KEY_LONG_TIME)
            {
                ptypeKey->state &= 0x00FF;
                ptypeKey->state |= keyLong;
                return ptypeKey->state;
            }
            break;

        case keyLong | keyAdd:
            if((lTimeNow - ptypeKey->timePress) >= KEY_CONTINUE_TIME)
            {
                ptypeKey->state &= 0x00FF;
                ptypeKey->state |= keyContinuous;
                return ptypeKey->state;
            }
            break;

        case keyContinuous | keyAdd:
            break;

        default : break;
    }

    return keyNormal;
}

/*
 * Return:      KeyStateEnum：按键状态机的状态
 * Parameters:  ptypeKey：按键结构消息
 * Description: 按键状态机信息获取
 */
KeyStateEnum enumKeyStateMachine(KeyType *ptypeKey)
{
    uint32_t uiNew, uiTimeNow;
    KeyStateEnum enumState;

    if((ptypeKey == NULL) || (ptypeKey->uiKeyValueGet == NULL))
        return keyNormal;

    /* 键值获取 */
    if(((uiNew = ptypeKey->uiKeyValueGet()) != 0) || (ptypeKey->valueLast != 0))
    {
        uiTimeNow = lTimebaseGet() / 1000;

        /* 按键状态判断 */
        enumState = enumKeyStateGet(uiNew, ptypeKey->valueLast);

        /* 按键状态转换 */
        switch(enumState)
        {
            /* 记录按键按下时间、按下总键值，松开按键键值清零 */
            case keyAdd:
                ptypeKey->valuePress = uiNew;
                ptypeKey->timePress = uiTimeNow;
                ptypeKey->valueLoosen = 0;
                ptypeKey->state = keyAdd;
                ptypeKey->valueLast = uiNew;
                break;

            /* 记录按键松开时间、松开总键值 */
            case keyCut:
                ptypeKey->valueLoosen |= ptypeKey->valueLast & (~uiNew);
                ptypeKey->timeLoosen = uiTimeNow;
                ptypeKey->state &= ~0x00FF;
                ptypeKey->state |= keyCut;
                ptypeKey->valueLast = uiNew;
                return ptypeKey->state;

            /* 记录按键按下时间、按下总键值、松开时间、松开总键值 */
            case keyAddAndCut:
                ptypeKey->valuePress = uiNew;
                ptypeKey->timePress = uiTimeNow;
                ptypeKey->valueLoosen |= ptypeKey->valueLast & (~uiNew);
                ptypeKey->timeLoosen = uiTimeNow;
                ptypeKey->valueLast = uiNew;
                break;

            case keyEqual:
                return enumKeyTimeStateGet(ptypeKey);

            default: break;
        }
    }

    return keyNormal;
}
